﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OverStore.Configuration.Builder;
using System.Data.SqlServerCe;
using OverStore.Configuration.Builder.Fluent;
using OverStore.Configuration.Components;
using OverStore.Exceptions;
using OverStore.Runtime.Storage;
using OverStore.Runtime.ObjectRepository.ErrorTransformer;

namespace OverStore.TutorialAsTest.UnitTest
{
    [TestClass]
    public class ErrorTransforming
    {
        // CREATE TABLE UniqName(id uniqueidentifier not null, name nvarchar(100) not null, code nvarchar(100) not null);
        // ALTER TABLE UniqName ADD CONSTRAINT PK_UniqName PRIMARY KEY (Id);
        // ALTER TABLE UniqName ADD CONSTRAINT UK_UniqName_Name UNIQUE (name);
        // ALTER TABLE UniqName ADD CONSTRAINT UK_UniqName_Code UNIQUE (code);

        public class UniqName
        {
            public Guid Id { get; set; }

            public string Name { get; set; }

            public string Code { get; set; }
        }

        private IPersistenceSessionFactory CreateConfig(string connectionString)
        {
            return OverStoreFluent.Configure()
                        .LogToDebug()
                        .ConnectToDatabase<SqlCeConnection>(connectionString, ProcessOpenedReadersMode.ForciblyCloseReaders)
						.MapClassToTable<UniqName, Guid>("UniqName")
							.MapKey("id", e => e.Id, (e, v) => e.Id = v,
                                        Component.IdentifierGenerator.Guid<UniqName>())
                            .MapScalarValue<string>("name", e => e.Name, (e, v) => e.Name = v)
                            .MapScalarValue<string>("code", e => e.Code, (e, v) => e.Code = v)
                            .TransformError<SqlCeException>("UK_UniqName_Name", MessageMatchType.MessageContainsPattern, "Name must be unique")
                            .TransformError<SqlCeException>("UK_UniqName_Code", MessageMatchType.MessageContainsPattern, "Code must be unique")
						.EndTableMapping()
                    .End();
        }

        [TestMethod]
        public void CorrectUpdate()
        {
            var cs = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            var id = new Guid("82302d6a-43f4-440b-93f0-518cca207400");
            using (var session = CreateConfig(cs).CreateSession())
            {
                var entity = session.GetByIdentifier<UniqName, Guid>(id);
                Assert.AreEqual(id, entity.Id);
                Assert.AreEqual("object one", entity.Name);
                Assert.AreEqual("223123", entity.Code);

                entity.Name = "changed";
                session.Save(entity);
            }
            using (var session = CreateConfig(cs).CreateSession())
            {
                var entity = session.GetByIdentifier<UniqName, Guid>(id);
                Assert.AreEqual("changed", entity.Name);
            }
        }

        [TestMethod]
        public void InsertDuplicateName()
        {
            var cs = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            using (var session = CreateConfig(cs).CreateSession())
            {
                var newEntity = new UniqName { Name = "object one", Code = "876543" };
                try
                {
                    session.Save(newEntity);
                    Assert.Fail("Exception about inserting duplicated values must be thrown.");
                }
                catch (PersistenceOperationFailedException ex)
                {
                    Assert.AreEqual("Name must be unique", ex.Message);
                }
            }
        }

        [TestMethod]
        public void UpdateDuplicateCode()
        {
            var cs = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            using (var session = CreateConfig(cs).CreateSession())
            {
                var id = new Guid("82302d6a-43f4-440b-93f0-518cca207400");
                var entity = session.GetByIdentifier<UniqName, Guid>(id);
                entity.Code = "223311";
                try
                {
                    session.SaveAll();
                    Assert.Fail("Exception about error on inserting duplicated values in code column must be thrown.");
                }
                catch (PersistenceOperationFailedException ex)
                {
                    Assert.AreEqual("Code must be unique", ex.Message);
                }
            }
        }

        [TestMethod]
        public void UpdateWithErrorAndSaveCorrect()
        {
            var id = new Guid("82302d6a-43f4-440b-93f0-518cca207400");
            var cs = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            using (var session = CreateConfig(cs).CreateSession())
            {
                var entity = session.GetByIdentifier<UniqName, Guid>(id);
                entity.Name = "object two";
                try
                {
                    session.Save(entity);
                    Assert.Fail("Name is not unique");
                }
                catch (PersistenceOperationFailedException ex)
                {
                    Assert.AreEqual("Name must be unique", ex.Message);
                }
                entity.Name = "changed";
                session.Save(entity);
            }
            using (var session = CreateConfig(cs).CreateSession())
            {
                var entity = session.GetByIdentifier<UniqName, Guid>(id);
                Assert.AreEqual("changed", entity.Name);
            }
        }
    }
}
